--- import Layout from '../../../layouts/Layout.astro'; import Breadcrumb from '../../../components/Breadcrumb.astro'; import { getBrandBySlugFromDB, getModelsByBrand, getColorsByModel, getModelContent, getProductIdsOffersLastUpdated } from '../../../lib/products'; import { getBlogPostsForModel } from '../../../lib/blog'; import UspStrip from '../../../components/UspStrip.astro'; import QuickFacts from '../../../components/QuickFacts.astro'; const { slug, model: modelSlug } = Astro.params; const dbBrand = await getBrandBySlugFromDB(slug!); if (!dbBrand) return Astro.redirect('/merken'); const brandName = dbBrand.name; // Find model name from slug const models = await getModelsByBrand(slug!); const modelInfo = models.find(m => m.slug === modelSlug); if (!modelInfo) return Astro.redirect(`/merken/${slug}`); const modelName = modelInfo.name; // Get all color variants, SEO content, and related blog posts for this model const [colors, modelContent, relatedPosts] = await Promise.all([ getColorsByModel(slug!, modelName), getModelContent(slug!, modelSlug!), getBlogPostsForModel(brandName, modelName), ]); // If only 1 color, redirect straight to the color page if (colors.length === 1) { return Astro.redirect(`/merken/${slug}/${modelSlug}/${colors[0].slug}`, 302); } const lowestPrice = colors.length > 0 ? Math.min(...colors.map(c => c.lowestPrice)) : 0; const highestPrice = colors.length > 0 ? Math.max(...colors.map(c => c.lowestPrice)) : 0; const totalProducts = colors.reduce((sum, c) => sum + c.count, 0); const priceRange = lowestPrice === highestPrice ? `€${lowestPrice.toFixed(2).replace('.', ',')}` : `€${lowestPrice.toFixed(2).replace('.', ',')} - €${highestPrice.toFixed(2).replace('.', ',')}`; // QuickFacts data const modelProductIds = colors.map(c => c.productId).filter((id): id is number => typeof id === 'number'); const modelOffersLastUpdated = await getProductIdsOffersLastUpdated(modelProductIds); const quickFactsUpdatedLabel = modelOffersLastUpdated ? new Date(modelOffersLastUpdated).toLocaleString('nl-NL', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' }) : new Date().toLocaleString('nl-NL', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' }); const lowestPriceStr = `€${lowestPrice.toFixed(2).replace('.', ',')}`; const quickFactsSummary = lowestPrice > 0 ? `Laagste prijs vandaag: ${lowestPriceStr} · ${colors.length} ${colors.length === 1 ? 'kleur' : 'kleuren'} · ${totalProducts} ${totalProducts === 1 ? 'variant' : 'varianten'} · Laatst bijgewerkt: ${quickFactsUpdatedLabel}.` : `${colors.length} ${colors.length === 1 ? 'kleur' : 'kleuren'} · ${totalProducts} ${totalProducts === 1 ? 'variant' : 'varianten'} · Laatst bijgewerkt: ${quickFactsUpdatedLabel}.`; const quickFacts: { label: string; value: string }[] = [ { label: 'Laagste prijs', value: priceRange }, { label: 'Kleuren', value: String(colors.length) }, { label: 'Varianten', value: String(totalProducts) }, { label: 'Bijgewerkt', value: quickFactsUpdatedLabel }, ]; const INITIAL_VISIBLE = 24; const visibleColors = colors.slice(0, INITIAL_VISIBLE); const hiddenColors = colors.slice(INITIAL_VISIBLE); const title = `${brandName} ${modelName} kopen? Vergelijk ${colors.length} kleuren vanaf €${lowestPrice.toFixed(2).replace('.', ',')} | SneakerPicks`; const description = `${brandName} ${modelName} in ${colors.length} kleuren vergelijken bij Nederlandse webshops. ${totalProducts} varianten beschikbaar vanaf ${priceRange}. Vind de laagste prijs.`; const canonicalUrl = `https://sneakerpicks.nl/merken/${slug}/${modelSlug}`; // JSON-LD structured data const modelDateModifiedIso = (modelOffersLastUpdated ?? new Date()).toISOString(); const jsonLd = { "@context": "https://schema.org", "@type": "ItemList", "inLanguage": "nl-NL", "name": `${brandName} ${modelName}`, "description": description, "url": canonicalUrl, "numberOfItems": colors.length, "dateModified": modelDateModifiedIso, "publisher": { "@type": "Organization", "name": "SneakerPicks", "url": "https://sneakerpicks.nl", "logo": { "@type": "ImageObject", "url": "https://sneakerpicks.nl/logo.svg" } }, "itemListElement": colors.map((c, i) => ({ "@type": "ListItem", "position": i + 1, "item": { "@type": "Product", "inLanguage": "nl-NL", "name": `${brandName} ${modelName} ${c.name}`, "url": `https://sneakerpicks.nl/merken/${slug}/${modelSlug}/${c.slug}`, ...(c.image ? { "image": c.image } : {}), "brand": { "@type": "Brand", "name": brandName }, "offers": { "@type": "AggregateOffer", "lowPrice": c.lowestPrice, "priceCurrency": "EUR", "availability": "https://schema.org/InStock" } } })) }; const breadcrumbLd = { "@context": "https://schema.org", "@type": "BreadcrumbList", "inLanguage": "nl-NL", "itemListElement": [ { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://sneakerpicks.nl/" }, { "@type": "ListItem", "position": 2, "name": "Merken", "item": "https://sneakerpicks.nl/merken" }, { "@type": "ListItem", "position": 3, "name": brandName, "item": `https://sneakerpicks.nl/merken/${slug}` }, { "@type": "ListItem", "position": 4, "name": modelName, "item": canonicalUrl } ] }; const faqLd = modelContent?.faq?.length ? { "@context": "https://schema.org", "@type": "FAQPage", "inLanguage": "nl-NL", "mainEntity": modelContent.faq.map(item => ({ "@type": "Question", "name": item.question, "acceptedAnswer": { "@type": "Answer", "text": item.answer } })) } : null; --- )} {colors.length === 0 && (

Geen kleuren gevonden voor {brandName} {modelName}.

Bekijk alle {brandName} sneakers →
)} {(modelContent?.description || modelContent?.pdpBody) && (

Over de {brandName} {modelName}

{(modelContent.description || modelContent.pdpBody || '').split('\n\n').map(paragraph => (

{paragraph}

))}
)} {modelContent?.faq && modelContent.faq.length > 0 && (

Veelgestelde vragen over de {brandName} {modelName}

{modelContent.faq.map((item, i) => (
{item.question}
{item.answer}
))}
)} {models.filter(m => m.slug !== modelSlug).length > 0 && (

Andere {brandName} modellen

Alle modellen →
{models.filter(m => m.slug !== modelSlug).slice(0, 12).map(m => ( {m.name} ({m.count}) ))}
)} {relatedPosts.length > 0 && (

{brandName} {modelName} op ons blog

)}